package com.stegniy.queue;

import java.util.NoSuchElementException;

public class ArrayQueue<E> implements Queue<E> {

    private static final int DEFAULT_CAPACITY = 10;

    private E[] items;
    private int maxSize;
    private int size;
    private int tail;
    private int head;

    public ArrayQueue() {
        maxSize = DEFAULT_CAPACITY;
        items = (E[]) new Object[maxSize];
        head = 0;
        tail = maxSize -1;
        size = 0;
    }

    public ArrayQueue(int capacity) {
        maxSize = capacity;
        items = (E[]) new Object[maxSize];
        head = 0;
        tail = maxSize -1;
        size = 0;
    }


    public int size() {
        return size;
    }

    public boolean isEmpty() {
        return size == 0;
    }

    public boolean isFull() {
        return size == maxSize;
    }

    /*Retrieves, but does not remove, the head of this queue*/
    public E element() {
        if (!isEmpty()) {
            return (E) items[head];
        } else {
            throw new NoSuchElementException();
        }
    }

    /*Inserts the specified element into this queue if it is possible to do
      so immediately without violating capacity restrictions*/
    public boolean offer (E e) {
        if (isFull()) {
            int newSize = maxSize * 2;
            E[] newItems = (E[]) new Object[newSize];
            int i = head;
            for (int k = 0; k < size; k++) {
                newItems[k] = items[i];
                i = (i + 1) % maxSize;
            }
            items = newItems;
            head = 0;
            tail = size - 1;
            maxSize = newSize;
        }
        tail = (tail + 1) % maxSize;
        items[tail] = e;
        ++size;
        return true;
    }

    /*Retrieves, but does not remove, the head of this queue,
      or returns null if this queue is empty*/
    public E peek() {
        E item = null;
        if (!isEmpty()) {
            item = items[head];
        }
        return item;
    }

    /*Retrieves and removes the head of this queue,
      or returns null if this queue is empty*/
    public E poll() {
        if (!isEmpty()) {
            E item = items[head];
            items[head] = null;
            head = (head + 1) % maxSize;
            size--;
            return item;
        } else {
            return null;
        }
    }

    /*Retrieves and removes the head of this queue*/
    public E remove() {
        if (isEmpty()) {
            throw new NoSuchElementException("the queue is empty");
        } else {
            E item = items[head];
            items[head] = null;
            head = (head + 1) % maxSize;
            size--;
            return item;
        }
    }
}